package com.itlong.cloud.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardSyncDataFloorRelationDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardSyncMessageDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardSyncTaskStatusDTO;
import com.itlong.cloud.POJO.PO.DeviceElevatorFloorConfigPO;
import com.itlong.cloud.POJO.PO.SmartCardPushPO;
import com.itlong.cloud.POJO.PO.TimeTaskPushAnalysisPO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.dao.IDeviceElevatorFloorConfigDao;
import com.itlong.cloud.dao.ISmartCardSyncDataPushDao;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.SmartCardSyncDataStatusEnum;
import com.itlong.cloud.service.ISmartCardSyncDataPushService;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <desc>
 *      与旺龙一卡通对接-操作一卡通push云端的数据的接口实现类
 * </desc>
 *
 * @createDate 2017-11-01
 */
@Service
public class SmartCardSyncDataPushServiceImpl implements ISmartCardSyncDataPushService {
    private static final Logger LOG = LoggerFactory.getLogger(SmartCardSyncDataPullServiceImpl.class);

    @Autowired
    private ISmartCardSyncDataPushDao iSmartCardSyncDataPushDao;


    @Autowired
    RedisService redisService;  //Reids操作对象

    @Autowired
    IDeviceElevatorFloorConfigDao iDeviceElevatorFloorConfigDao;

    /**
     * <desc>
     *     在保存同步的楼层对应表前进行数据检查，若上不存在，则需初始化1-112层的数据
     * </desc>
     *
     * @param  deviceUnique 设备唯一Id
     * @return 无
     * @author LewisLouis
     * @createDate 2017-12-26
     */
    private void preHandleBeforeSaveFloorConfig(String deviceUnique){

        List<DeviceElevatorFloorConfigPO> floorConfigPOS = iDeviceElevatorFloorConfigDao.getFloorConfigIdList(deviceUnique);
        //若有112数据无需处理
        if ((floorConfigPOS != null) && (floorConfigPOS.size() == PlatformConstants.MAX_ELEVATOR_FLOORNUM)){
            return;
        }

        //清理不足112层的脏数据
        if ((floorConfigPOS != null) && (floorConfigPOS.size() < PlatformConstants.MAX_ELEVATOR_FLOORNUM)){
            iDeviceElevatorFloorConfigDao.delByDeviceUnique(deviceUnique);
        }
        Integer naturalFloor = 1;
        List<DeviceElevatorFloorConfigPO> floorConfigPOList = new ArrayList<>();
        for (int floorIndex = 1; floorIndex <= PlatformConstants.MAX_ELEVATOR_FLOORNUM; floorIndex++) {
            DeviceElevatorFloorConfigPO floorConfigPO = new DeviceElevatorFloorConfigPO("", deviceUnique, (naturalFloor++).toString());
            floorConfigPO.setStatus(DataStatusEnum.NORMAL.getType());
            Date date = new Date();
            floorConfigPO.setLogicalFloor(String.format("%d层",floorIndex));
            floorConfigPO.setFloorNum(floorIndex);
            floorConfigPO.setDetectFloor(floorIndex+"");
            floorConfigPO.setTerminalFloor(floorIndex+"");
            floorConfigPO.setCreateTime(date);
            floorConfigPO.setUpdateTime(date);
            floorConfigPOList.add(floorConfigPO);
        }
        if (!floorConfigPOList.isEmpty()) {
            iDeviceElevatorFloorConfigDao.saveBatch(floorConfigPOList);
        }
    }

    /**
     * <desc>
     *     初步处理一卡通推送给云端的数据（放入相应的push表中）
     * </desc>
     *
     * @param smartCardSyncMessageDTO 一卡通推送到云端同步数据.
     * @author LewisLouis
     * @createDate 2017-12-20
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void receiveSyncDataFromSmartCard(SmartCardSyncMessageDTO smartCardSyncMessageDTO) throws Exception {
        String tableName = String.format("%s%s", PlatformConstants.SMARTCARD_TABLENAME_PREFIX_PUSH,smartCardSyncMessageDTO.getProjectId());
        List<SmartCardPushPO> smartCardPushPOS = getSmartCardPushPOBySmartCardSyncDataDTO(smartCardSyncMessageDTO,
                tableName);
        if (smartCardPushPOS.isEmpty()){
            LOG.info(String.format("一卡通同步到云端的数据异常:%s",smartCardSyncMessageDTO));
            return;
        }

        beforeHandlePushTable(tableName);
        //如果是楼层映射表信息 立即同步
        if(smartCardSyncMessageDTO.getDataType() == 6) {
            //此处处理线下平台ARM电梯当楼层名称为空时，则只需更新相对应的端子号，目的防止其他字段被错误信息替换
            boolean mark = false;
            if(smartCardPushPOS!=null && smartCardPushPOS.size()>0){
                SmartCardSyncDataFloorRelationDTO floorRelationDTO = JSON.parseObject(smartCardPushPOS.get(0).getSyncData(), SmartCardSyncDataFloorRelationDTO.class);
                String deviceUnique = floorRelationDTO.getDeviceUnique();
                Integer count = iSmartCardSyncDataPushDao.isBlueElevatorByDeviceUnique(deviceUnique);
                if(count>0 && !smartCardPushPOS.get(0).getSyncData().contains("logicalFloor")){
                    mark = true;
                }
            }
            for (SmartCardPushPO po : smartCardPushPOS) {
                po.setSyncStatus(3);
                //解析
                SmartCardSyncDataFloorRelationDTO smartCardSyncDataFloorRelationDTO = JSON.parseObject(po.getSyncData(), SmartCardSyncDataFloorRelationDTO.class);
                DeviceElevatorFloorConfigPO deviceElevatorFloorConfigPO = new DeviceElevatorFloorConfigPO();
                BeanUtils.copyProperties(smartCardSyncDataFloorRelationDTO, deviceElevatorFloorConfigPO);
                deviceElevatorFloorConfigPO.setFloorNum(smartCardSyncDataFloorRelationDTO.getFloorReal());
                deviceElevatorFloorConfigPO.setDetectFloor(StringUtils.isNotBlank(smartCardSyncDataFloorRelationDTO.getDetectFloor())
                        && smartCardSyncDataFloorRelationDTO.getDetectFloor().equals("0") ? "-" : smartCardSyncDataFloorRelationDTO.getDetectFloor());
                deviceElevatorFloorConfigPO.setLogicalFloor(smartCardSyncDataFloorRelationDTO.getLogicalFloor());
                Date date = new Date();
                deviceElevatorFloorConfigPO.setTerminalFloor(smartCardSyncDataFloorRelationDTO.getTerminalNum().equals("0") ? "-" : smartCardSyncDataFloorRelationDTO.getTerminalNum());
                deviceElevatorFloorConfigPO.setNaturalFloor(smartCardSyncDataFloorRelationDTO.getNaturalFloor());
                deviceElevatorFloorConfigPO.setCreateTime(date);
                deviceElevatorFloorConfigPO.setUpdateTime(date);
                deviceElevatorFloorConfigPO.setStatus(DataStatusEnum.NORMAL.getType());
                this.preHandleBeforeSaveFloorConfig(deviceElevatorFloorConfigPO.getDeviceUnique());
                List<DeviceElevatorFloorConfigPO> deviceElevatorFloorConfigPOS = iDeviceElevatorFloorConfigDao.getElevatorFloorConfigByPO(deviceElevatorFloorConfigPO);
                if ((deviceElevatorFloorConfigPOS == null || (deviceElevatorFloorConfigPOS.isEmpty()))) {
                    iDeviceElevatorFloorConfigDao.save(SqlUtil.durableData(deviceElevatorFloorConfigPO, PlatformConstants.TABLE_SAVE));
                } else {
                    if(mark){
                        iDeviceElevatorFloorConfigDao.updateFloorRelationByTerminalFloorForSmartCard(deviceElevatorFloorConfigPO);
                    }else{
                        iDeviceElevatorFloorConfigDao.updateFloorRelationForSmartCard(deviceElevatorFloorConfigPO);
                    }
                    //String projectId = StringHandlerUtil.copySubStr(deviceElevatorFloorConfigPO.getDeviceUnique(),0,8);
                    //this.sendMessageForDeviceChanged(projectId); //转移到定时任务中，批量操作后再执行通知
                }
            }
        }
        iSmartCardSyncDataPushDao.batchSavePushData(tableName,smartCardPushPOS);
        //存储有数据需要解析的push表的信息
        this.markPushTableNeedHandle(tableName);
    }

    /**
     * <desc>
     * 解析Push表中数据的定时任务获取有数据变动的push表
     * <desc/>
     *
     * @param mark 数据变动标记 0:无变动 | 1:有变动
     * @return List<TimeTaskPushAnalysisPO> 定时任务临时表数据集
     * @author zhangs
     * @createDate 2017/11/3
     */
    @Override
    public List<TimeTaskPushAnalysisPO> getPushTableName(Integer mark) {
        if(mark == null) {
            return new ArrayList<>();
        }
        Map<String, Object> param = new HashMap<>();
        param.put("mark", mark);
        return iSmartCardSyncDataPushDao.getPushTableName(param);
    }

    /**
     * <desc>
     *     获取是否有任意一卡通项目推送给云端的数据需处理.
     * </desc>
     *
     * @return SmartCardSyncTaskStatusDTO 定时任务（分析一卡通推送给云端的数据）的运行状态.
     * @author LewisLouis
     * @createDate 2017-12-26
     */
    @Override
    public SmartCardSyncTaskStatusDTO getSmartCardSyncTaskStatus() {
        String taskInfo =  redisService.get(RedisConstant.SMART_CARD_HAS_SYNC_PUSH_DATA_KEY);
        SmartCardSyncTaskStatusDTO taskStatusDTO;
        if (StringUtils.isBlank(taskInfo)){
            taskStatusDTO = new SmartCardSyncTaskStatusDTO();
            taskStatusDTO.setHasPushDataNeedToHandle(true);
            taskStatusDTO.setTaskRunnig(false);
            this.setSmartCardSyncTaskStatus(taskStatusDTO);
        } else {
            try {
                taskStatusDTO = JSONObject.parseObject(taskInfo, SmartCardSyncTaskStatusDTO.class);
            } catch (Exception e) {
                LOG.error("获取一卡通数据分析定时任务状态失败",e);
                taskStatusDTO = new SmartCardSyncTaskStatusDTO();
                taskStatusDTO.setHasPushDataNeedToHandle(true);
                taskStatusDTO.setTaskRunnig(false);
            }
        }
        return taskStatusDTO;
    }

    /**
     * <desc>
     * 设置是否有任意一卡通项目推送给云端的数据需处理.
     * </desc>
     *
     * @param taskStatus 一卡通同步任务运行状态
     * @return
     * @author LewisLouis
     * @createDate 2017-12-26
     */
    @Override
    public void setSmartCardSyncTaskStatus(SmartCardSyncTaskStatusDTO taskStatus) {
        try {
            redisService.set(RedisConstant.SMART_CARD_HAS_SYNC_PUSH_DATA_KEY,JSONObject.toJSONString(taskStatus));
        } catch (Exception e) {
           LOG.error("更新一卡通数据分析定时任务状态失败",e);
        }
    }


    /**
     * <desc>
     *     定时任务获取push表中未解析的数据
     * <desc/>
     *
     * @param tableName 查询条件
     * @return List<SmartCardPushPO> 旺龙一卡通push的数据集
     * @author zhangs
     * @createDate 2017/11/3
     */
    @Override
    public List<SmartCardPushPO> getUnresolvedPushData(String tableName) {
        return iSmartCardSyncDataPushDao.getUnresolvedPushData(tableName);
    }

    /**
     * <desc>
     *     更新表time_task_push_analysis中push表名对应的数据处理状态
     * <desc/>
     *
     * @param timeTaskPushAnalysisPO 存储有数据需要解析的push表信息的定时任务临时表
     * @return
     * @author zhangs
     * @createDate 2017/11/3
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateTimeTaskPushStatus(TimeTaskPushAnalysisPO timeTaskPushAnalysisPO) {
        String tableName = timeTaskPushAnalysisPO.getTableName();
        Integer mark = timeTaskPushAnalysisPO.getMark();
        if (StringUtils.isBlank(tableName) || (mark == null)) {
            return;
        }
        iSmartCardSyncDataPushDao.updateTimeTaskPushStatus(timeTaskPushAnalysisPO);
    }

    /**
     * <desc>
     *      更新push表中已完成解析的数据的状态
     * <desc/>
     *
     * @param tableName Push表名
     * @param id 数据唯一标识
     * @return
     * @author zhangs
     * @createDate 2017/11/16
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void setSyncPushDataResolvedById(String tableName, Integer id) {

        iSmartCardSyncDataPushDao.setSyncPushDataResolvedById(tableName,id);
    }

    /**
     * <desc>
     * 将已处理的一卡通同步到云端到数据进行转移.
     * </desc>
     *
     * @param tableName push表
     * @return xx
     * @author LewisLouis
     * @createDate 2018-01-09
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void movePushDataToColdTable(String tableName) {
        iSmartCardSyncDataPushDao.movePushDataToColdTable(tableName);

        iSmartCardSyncDataPushDao.removePushData(tableName);
    }


    /**
    * <desc>
    *     根据一卡通同步消息解析出同步数据列表用于存库.
    * </desc>
    *
    * @param  smartCardSyncMessageDTO 一卡通云端同步消息
    * @return 同步数据列表
    * @author LewisLouis
    * @createDate 2017-12-20
    */
    private List<SmartCardPushPO> getSmartCardPushPOBySmartCardSyncDataDTO(SmartCardSyncMessageDTO smartCardSyncMessageDTO,
                                                                           String tableName){

        List<SmartCardPushPO> smartCardPushPOS = JSON.parseArray(smartCardSyncMessageDTO.getInfo(),
                SmartCardPushPO.class);
        List<SmartCardPushPO> errList = null ;
        for (SmartCardPushPO smartCardPushPO: smartCardPushPOS){
            if (StringUtils.isBlank(smartCardPushPO.getSyncSerialNo())
                    || (StringUtils.isBlank(smartCardPushPO.getSyncData())
            ||(StringUtils.isBlank(smartCardPushPO.getDataUid())))){
                if (null == errList){
                    errList = new ArrayList<>();
                }
                errList.add(smartCardPushPO);
                continue;
            }
            smartCardPushPO.setProjectId(smartCardSyncMessageDTO.getProjectId());
            smartCardPushPO.setSyncVersion(smartCardSyncMessageDTO.getSyncVersion());
            smartCardPushPO.setDataType(smartCardSyncMessageDTO.getDataType());
            smartCardPushPO.setSyncStatus(SmartCardSyncDataStatusEnum.NOT_SYNC.getType());
            smartCardPushPO.setStatus(DataStatusEnum.NORMAL.getType());
            smartCardPushPO.setCreateTime(new Date());
        }
        if ((null != errList) && (!errList.isEmpty())){
            LOG.info(String.format("一卡通推送给云端的同步数据存在非法内容,放弃处理:%s",JSON.toJSONString(errList)));
            smartCardPushPOS.retainAll(errList);
        }
        iSmartCardSyncDataPushDao.createPushTable(tableName);
        return smartCardPushPOS;
    }


    /**
     * <desc>
     *      记录数据需要解析的push表信息
     * <desc/>
     *
     * @param tableName push表名
     * @return
     * @author zhangs
     * @createDate 2017/10/31
     */
    private void markPushTableNeedHandle(String tableName) {
        SmartCardSyncTaskStatusDTO statusDTO = this.getSmartCardSyncTaskStatus();
        statusDTO.setHasPushDataNeedToHandle(true);
        this.setSmartCardSyncTaskStatus(statusDTO);
        Map<String, Object> param = new HashMap<>();
        param.put("tableName", tableName);
        List<TimeTaskPushAnalysisPO> timeTaskPushAnalysisPOS = iSmartCardSyncDataPushDao.getPushTableName(param);
        TimeTaskPushAnalysisPO timeTaskPushAnalysisPO = new TimeTaskPushAnalysisPO();
        timeTaskPushAnalysisPO.setTableName(tableName);
        timeTaskPushAnalysisPO.setMark(PlatformConstants.HAS_SMART_CARD_PUSH_DATA_FOR_ANALYSIS);
        timeTaskPushAnalysisPO.setStatus(DataStatusEnum.NORMAL.getType());
        Date updateTime = new Date();
        timeTaskPushAnalysisPO.setUpdateTime(updateTime);
        if(timeTaskPushAnalysisPOS != null && !timeTaskPushAnalysisPOS.isEmpty()) {
            iSmartCardSyncDataPushDao.updateTimeTaskPushStatus(timeTaskPushAnalysisPO);
        } else {
            timeTaskPushAnalysisPO.setCreateTime(updateTime);
            iSmartCardSyncDataPushDao.savePushTableName(timeTaskPushAnalysisPO);
        }
    }

    /**
     * <desc>
     *     在操作（增、删、改、查记录）push记录表之前，先进行建表检查.
     * </desc>
     *
     * @param  tableName 表名
     * @author LewisLouis
     * @createDate 2017-12-26
     */
    private void beforeHandlePushTable(String tableName){
        String readisTable = redisService.get(tableName);
        if (StringUtils.isBlank(readisTable)){
            iSmartCardSyncDataPushDao.createPushTable(tableName);
            redisService.set(tableName,tableName);
        };
    }
}
